package view;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;

import battleModel.CampaignModel;
import battleModel.Difficulty;
import battleModel.Tank;

/**
 * 
 * 
 * @author Kyle Bush
 * 
 */
@SuppressWarnings("serial")
public class CampaignView extends MasterViewPanel {

	// File Locations
	private final String background = "images/backgrounds/campaignSelect.png";
	private final String gameList = "savedGames/gameList.txt";
	private final String mapFiles = "texts/maps.txt";
	private BufferedImage img;

	private JPanel levelPanel, optionsPanel;
	private JLabel tank, map;
	private JTextField playerName;
	private GameButton[] levels;
	private JRadioButton[] colors, difficulty;
	private boolean levelSelected, transitioning;
	private float alpha;

	// A Map of map images
	private Map<Integer, ImageIcon> maps;

	private Tank player;
	private String currColor, currLevel, currDifficulty;

	private final int COLORS = 8;

	/**
	 * Sets up a Campaign view
	 * 
	 * @param m
	 */
	public CampaignView(MasterView m) {
		super(m);
		player = new Tank();

		transitioning = true;
		alpha = 0.2f;
		currLevel = "0";

		getMapFiles();
		setUpLayout();
		setUpPanels();
	}

	private void getMapFiles() {
		// Text file of all maps
		Scanner readFile = null;
		try {
			readFile = new Scanner(new File(mapFiles));
		} catch (FileNotFoundException e) {
		}

		// Map of all maps
		maps = new HashMap<Integer, ImageIcon>();
		String temp;
		int levelNum = 0;
		while (readFile.hasNext()) {
			temp = readFile.nextLine();
			maps.put(levelNum, (new ImageIcon(temp)));
			levelNum++;
		}
	}

	private void setUpLayout() {
		this.setLayout(null);
	}

	private void setUpPanels() {
		setUpLevelPanel();
		setUpOptionsPanel();
		setUpTraverseButtons();
		drawBackGround();

		playerName.selectAll();
		playerName.requestFocus();
	}

	private void setUpLevelPanel() {
		levelPanel = new JPanel(new GridLayout(10, 2, 7, 7));
		levelPanel.setSize(450, 500);
		levelPanel.setLocation(20, 100);
		levelPanel.setOpaque(false);
		levelPanel.setVisible(true);
		this.add(levelPanel);

		setUpLevelButtons();
	}

	private void setUpOptionsPanel() {
		optionsPanel = new JPanel(new GridLayout(3, 0, 30, 30));
		optionsPanel.setSize(250, 295);
		optionsPanel.setLocation(570, 150);
		optionsPanel.setOpaque(false);
		optionsPanel.setVisible(true);
		this.add(optionsPanel);

		setUpNameAndDifficultyField();
		setUpColorOptions();
		setUpDisplayTankAndMap();
	}

	private void setUpLevelButtons() {
		String text = "";
		levels = new GameButton[CampaignModel.LEVELS];

		for (int i = 0; i < CampaignModel.LEVELS; i++) {
			text = "Level " + (i + 1) + "  Score: "
					+ player.getLevelScore(i + 1);
			levels[i] = new GameButton(m.getIcon("levelButton"),
					m.getIcon("levelButtonS"));
			levels[i].setSelectedIcon(m.getIcon("levelButtonsS"));
			levels[i].setDisabledIcon(m.getIcon("lockedLevel"));
			levels[i].setActionCommand("" + (i + 1));
			levels[i].addActionListener(new LevelSelectListener());

			if (i + 1 > player.getMaxLevel()){
				levels[i].setEnabled(true);
			levels[i].setText(text);}
			else
				levels[i].setText(text);

			levelPanel.add(levels[i]);
			text = null;
		}
		levelSelected = false;
	}

	private void setUpNameAndDifficultyField() {
		JPanel namePanel = new JPanel(new GridLayout(3, 0, 0, 5));
		namePanel.setOpaque(false);

		JLabel header = new JLabel("ENTER YOUR NAME");
		header.setForeground(Color.WHITE);
		header.setFont(new Font("Stencil", Font.PLAIN, 25));

		playerName = new JTextField("<name>", 25);
		playerName.setOpaque(false);
		playerName.setForeground(Color.WHITE);
		playerName.setBackground(new Color(50, 50, 50, 200));

		JPanel radioPanel = new JPanel(new GridLayout(0, 3));
		radioPanel.setOpaque(false);
		
		String[] diff = {"Easy", "Med", "Hard"};
		difficulty = new JRadioButton[3];
		
		for(int i = 0; i < 3; i++){
			difficulty[i] = new JRadioButton(diff[i]);
			difficulty[i].setForeground(Color.WHITE);
			difficulty[i].addActionListener(new DifficultyListener());
			difficulty[i].setActionCommand(diff[i]);
			difficulty[i].setPressedIcon(difficulty[i].getSelectedIcon());
			
			radioPanel.add(difficulty[i]);
		}
		
		difficulty[0].setSelected(true);
		currDifficulty = "Easy";
		
		namePanel.add(header);
		namePanel.add(playerName);
		namePanel.add(radioPanel);

		optionsPanel.add(namePanel);
	}

	private void setUpColorOptions() {
		JPanel colorPanel = new JPanel(new GridLayout(2, 0));
		JPanel btnPanel = new JPanel(new GridLayout(2, 4));

		// Header of color selector
		JLabel header = new JLabel("SELECT A COLOR");
		header.setFont(new Font("Stencil", Font.PLAIN, 25));
		header.setForeground(Color.WHITE);

		// Color choose buttons
		colors = new JRadioButton[COLORS];
		String[] color = { "RD", "OR", "YL", "GN", "BL", "VT", "BK", "WT" };

		// Color button Images
		BufferedImage colorBtn = null, colorBtnS = null;
		try {
			colorBtn = ImageIO.read(new File("images/buttons/colors.png"));
			colorBtnS = ImageIO.read(new File("images/buttons/colorsS.png"));
		} catch (IOException e) {
		}

		// Set up buttons with images
		Image img1 = null, img2 = null;
		for (int i = 0; i < COLORS; i++) {
			img1 = colorBtn.getSubimage((i * 20), 0, 20, 20);
			img2 = colorBtnS.getSubimage((i * 20), 0, 20, 20);

			ImageIcon icon = new ImageIcon(img1);
			ImageIcon iconS = new ImageIcon(img2);

			colors[i] = new JRadioButton(icon);
			colors[i].setRolloverIcon(iconS);
			colors[i].setSelectedIcon(iconS);
			colors[i].setActionCommand(color[i]);
			colors[i].addActionListener(new ColorListener());

			// Default color "RED" selected
			if (i == 0) {
				colors[i].setSelected(true);
				currColor = "RD";
			}

			btnPanel.setOpaque(false);
			btnPanel.add(colors[i]);
		}

		colorPanel.add(header);
		colorPanel.add(btnPanel);
		colorPanel.setOpaque(false);

		optionsPanel.add(colorPanel);
	}

	private void setUpTraverseButtons() {
		GameButton start = new GameButton(m.getIcon("start"),
				m.getIcon("startS"));
		GameButton back = new GameButton(m.getIcon("back"), m.getIcon("backS"));

		start.setLocation(570, 480);
		back.setLocation(550, 540);

		start.setSize(300, 50);
		back.setSize(300, 50);
 
		start.addActionListener(new StartGameListener());
		back.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				m.changeView(Views.LOAD, null);
			}
		});

		this.add(start);
		this.add(back);
	}

	private void setUpDisplayTankAndMap() {
		JPanel body = new JPanel(new GridLayout(0, 2)){
			protected void paintComponent(Graphics g){
				
			}
		};

		
		tank = new JLabel(new ImageIcon("images/tankDisplay/" + currColor
				+ ".png"));
		
		ImageIcon mapImg = getIcon(Integer.valueOf(currLevel));
		map = new JLabel(mapImg);
		

		body.setOpaque(false);
		body.add(tank);
		body.add(map);
		optionsPanel.add(body);
	}

	private void updateTank() {
		tank.setIcon(new ImageIcon("images/tankDisplay/" + currColor + ".png"));
	}

	private void updateMap() {
		map.setIcon(getIcon(Integer.valueOf(currLevel)));
	}

	private void drawBackGround() {
		try {
			img = ImageIO.read(new File(background));
		} catch (IOException e) {
			e.printStackTrace();
		}
		repaint();
	}

	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		Graphics2D g2d = (Graphics2D) g;

		// Set opacity
		g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
				alpha));
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);

		g.drawImage(img, 0, 0, this);
		
		if (transitioning)
			fadeIn();
	}

	private void fadeIn() {
		// Increase opacity and repaint
		alpha += 0.03f;
		if (alpha >= 1.0f) {
			alpha = 1.0f;
			transitioning = false;
		} else
			repaint();

		// Delay repainting
		try {
			Thread.sleep(5);
		} catch (InterruptedException e) {
		}
	}

	/* BUTTON LISTENERS */
	private class DifficultyListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			// Diff selected is different then that already selected
			if (!currDifficulty.equals(e.getActionCommand())) {
				for (int i = 0; i < 3; i++) {
					// Find selected color and deselect
					if (difficulty[i].getActionCommand().equals(currDifficulty))
						difficulty[i].setSelected(false);
				}

				// Set current color, update tank display
				currDifficulty = e.getActionCommand();
			} else {
				for (int i = 0; i < 3; i++) {
					if (difficulty[i].getActionCommand().equals(currDifficulty))
						difficulty[i].setSelected(true);
				}
			}

		}
	}

	private class ColorListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {

			// Color selected is different then that already selected
			if (!currColor.equals(e.getActionCommand())) {
				for (int i = 0; i < COLORS; i++) {
					// Find selected color and deselect
					if (colors[i].getActionCommand().equals(currColor))
						colors[i].setSelected(false);
				}

				// Set current color, update tank display
				currColor = e.getActionCommand();
				updateTank();
			} else {
				for (int i = 0; i < COLORS; i++) {
					if (colors[i].getActionCommand().equals(currColor))
						colors[i].setSelected(true);
				}
			}
		}
	}

	private class LevelSelectListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {

			// User level selection
			GameButton temp = levels[Integer.valueOf(e.getActionCommand()) - 1];

			// If level is already selected, set to unselected
			if (temp.levelSelected()) {
				temp.setIcon(m.getIcon("levelButton"));
				temp.setLevelSelected(false);
				currLevel = "0";
				levelSelected = false;
			} else {

				if (levelSelected) { // If level selected

					// Find level selected, and de-select
					for (int i = 0; i < CampaignModel.LEVELS; i++) {
						if (levels[i].levelSelected()) {
							levels[i].setLevelSelected(false);
							levels[i].setIcon(m.getIcon("levelButton"));
						}
					}
				}

				// Set level selected as selected
				temp.setIcon(m.getIcon("levelButtonS"));
				temp.setLevelSelected(true);
				currLevel = e.getActionCommand();
				levelSelected = true;
			}
			updateMap();
		}
	}

	private class StartGameListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {

			// If there is a level selected, the color selected and the
			// name of the player is set, and passed to the battle
			if (levelSelected) {

				player.setName(playerName.getText());
				player.setColor(currColor);
				switch(currDifficulty.compareTo(Difficulty.MEDIUM.toString())){
				case(-1):
					player.setDifficulty(Difficulty.EASY);
					break;
				case(0):
					player.setDifficulty(Difficulty.MEDIUM);
					break;
				case(1):
					player.setDifficulty(Difficulty.HARD);
					break;
				}

				try {
					FileOutputStream fos = new FileOutputStream("savedGames/"
							+ player.getName() + ".dat");
					ObjectOutputStream oos = new ObjectOutputStream(fos);
					oos.writeObject(player);

					BufferedWriter writer = new BufferedWriter(new FileWriter(
							gameList, true));
					writer.write((String) player.getName());
					writer.newLine();

					writer.close();
					oos.close();
					fos.close();

				} catch (FileNotFoundException e1) {
					JOptionPane.showMessageDialog(null, "File not found");
					e1.printStackTrace();
				} catch (IOException io) {
					JOptionPane.showMessageDialog(null, "IO Exception");
					io.printStackTrace();
				}

				m.changeView(Views.BATTLE, player);
			} else {
				JOptionPane.showMessageDialog(null, "Select a level");
			}
		}
	}

	private ImageIcon getIcon(int key) {
		return maps.get(key);
	}

	/**
	 * String representation of panel name.
	 */
	public String toString() {
		return "CAMPAIGN";
	}
}
